package com.ve.searcher.lucutil


//import org.apache.commons.lang.StringEscapeUtils;

import com.ve.searcher.pojo.EverythingFilePojo
import com.ve.searcher.pojo.SearchPojo
import org.apache.lucene.analysis.standard.StandardAnalyzer
import org.apache.lucene.document.Document
import org.apache.lucene.index.DirectoryReader
import org.apache.lucene.index.Term
import org.apache.lucene.queryparser.classic.QueryParser
import org.apache.lucene.search.*
import org.apache.lucene.search.BooleanClause.Occur
import org.apache.lucene.search.highlight.Highlighter
import org.apache.lucene.search.highlight.QueryScorer
import org.apache.lucene.search.highlight.SimpleFragmenter
import org.apache.lucene.search.highlight.SimpleHTMLFormatter
import java.text.SimpleDateFormat
import java.util.*

object LuceneSearch {

    @Throws(Exception::class)
    fun searchOther(q: String, field: String, maxHits: Int): ArrayList<DocumentWithHighlights> {

        val query = singleFieldQuery(q, field, maxHits)

        // return object
        val returnObjects = ArrayList<DocumentWithHighlights>()

        for (document in search(query, maxHits)) {
            returnObjects.add(DocumentWithHighlights(document, null))
        }

        return returnObjects
    }

    @Throws(Exception::class)
    fun searchBody(q: String, maxHits: Int): ArrayList<DocumentWithHighlights> {

        val query = singleFieldQuery(q, "body", maxHits)
        val highlighter = bodyHighlighter(query)

        // return object
        val returnObjects = ArrayList<DocumentWithHighlights>()

        for (document in search(query, maxHits)) {
            // make a new return object
            returnObjects.add(DocumentWithHighlights(document,
                    getFragments(document, highlighter)))
        }

        return returnObjects
    }

    @Throws(Exception::class)
    fun searchFile(searchPojo: SearchPojo): ArrayList<EverythingFilePojo>? {
        return null
    }

    @Throws(Exception::class)
    fun searchFile(q: String): ArrayList<EverythingFilePojo> {
        //Query query = singleFieldQuery(q, "body", 2);
        val query1 = PhraseQuery(0, "body", *q.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
        val returnObjects = ArrayList<EverythingFilePojo>()
        val fileset = HashSet<String>()
        val query2 = PhraseQuery.Builder().add(Term("file", q)).build()
        val booleanQuery = BooleanQuery.Builder()
                .add(query1, Occur.SHOULD)
                .add(query2, Occur.SHOULD)
                .build()



        for (document in search(booleanQuery, 9999999)) {
            val pojo = EverythingFilePojo()
            if (fileset.contains(document.get("path"))) {
                continue
            } else {
                fileset.add(document.get("path"))
            }
            pojo.fileName = document.get("file")
            pojo.filePath = document.get("path")
            returnObjects.add(pojo)
        }
        return returnObjects
    }


    @Throws(Exception::class)
    private fun bodyHighlighter(query: Query): Highlighter {

        val queryScorer = QueryScorer(query, "body")
        val formatter = SimpleHTMLFormatter("<mark style='background:pink'>", "</mark>")
        val highlighter = Highlighter(formatter, queryScorer) // Set the best scorer fragments

        //        Fragmenter fragmenter = new SimpleSpanFragmenter(queryScorer);
        val fragmenter = SimpleFragmenter(100)
        highlighter.textFragmenter = fragmenter // Set fragment to highlight
        highlighter.maxDocCharsToAnalyze = Integer.MAX_VALUE

        return highlighter
    }

    @Throws(Exception::class)
    private fun singleFieldQuery(q: String, field: String, maxHits: Int): Query {

        val parser = QueryParser(field, StandardAnalyzer())
        //        QueryParser parser = new QueryParser(field, MyAnalyzer.wrapperAnalyzer());// using stemming
        parser.allowLeadingWildcard = true

        // Escape the fileType string
        //q = StringEscapeUtils.escapeJava(q);

        // Remove eof
        //q = q.replaceAll("(\\r|\\n|\\t)", "");

        val query = parser.parse(QueryParser.escape(q))

        return query
    }

    @Throws(Exception::class)
    private fun search(query: Query, maxHits: Int): ArrayList<Document> {

        // index, index reader, and index searcher
        val index = LuceneInit.index
        val indexReader = DirectoryReader.open(index)
        val indexSearcher = IndexSearcher(indexReader)

        // get the top docs
        val topDocs = indexSearcher.search(query, maxHits)
        // make the return object
        val documents = ArrayList<Document>()

        // iterate through each document
        for (scoreDoc in topDocs.scoreDocs) {
            // get the document
            val document = indexSearcher.doc(scoreDoc.doc)
            documents.add(document)
        }

        // return the documents with highlight data
        return documents

    }

    // Multifield
    @Throws(Exception::class)
    fun multiSearch(
            body: String,
            tags: String,
            groupCodes: String,
            owner: String,
            fromDate: String,
            toDate: String,
            fileType: String,
            viewType: String,
            maxHits: Int,
            occurLogic: Occur
    ): ArrayList<DocumentWithHighlights> {
        var fromDate = fromDate
        var toDate = toDate

        // Create the boolean query builder
        val builder = BooleanQuery.Builder()

        // check if body is empty

        if (body != "") {

            // make the query
            val query = singleFieldQuery(body, "body", maxHits)

            // add the query to the builder
            builder.add(BooleanClause(query, Occur.MUST))
        }

        // check if tags is empty
        if (tags != "") {

            // make the query
            val query = singleFieldQuery(tags, "tags", maxHits)

            // add the query to the builder
            builder.add(BooleanClause(query, occurLogic))
        }

        // check if groupCodes is empty
        if (groupCodes != "") {

            // make the query
            val query = singleFieldQuery(groupCodes, "groupCodes", maxHits)

            // add the query to the builder
            builder.add(BooleanClause(query, occurLogic))
        }

        // check if owner is empty
        if (owner != "") {

            // make the query
            val query = singleFieldQuery(owner, "owner", maxHits)

            // add the query to the builder
            builder.add(BooleanClause(query, occurLogic))
        }

        // check if fromDate and toDate are empty
        if (fromDate != "" && toDate != "") {
            println(fromDate)
            fromDate = SimpleDateFormat("yyMMdd").format(
                    SimpleDateFormat("yy-MM-dd").parse(fromDate))

            toDate = SimpleDateFormat("yyMMdd").format(
                    SimpleDateFormat("yy-MM-dd").parse(toDate))
            println(fromDate)
            // make the query
            val query = singleFieldQuery(
                    "[$fromDate TO $toDate]",
                    "date", maxHits)

            // add the query to the builder
            builder.add(BooleanClause(query, occurLogic))
        }

        // check if owner is empty
        if (fileType != "") {


            val query = singleFieldQuery(fileType, "fileType", maxHits)
            builder.add(BooleanClause(query, occurLogic))
        }

        // check if viewType is empty
        if (viewType != "") {

            // make the query
            val query = singleFieldQuery(viewType, "viewType", maxHits)

            // add the query to the builder
            builder.add(BooleanClause(query, occurLogic))
        }

        builder.setMinimumNumberShouldMatch(1)
        val query = builder.build()

        val documents = search(query, maxHits)
        val highlighter = bodyHighlighter(query)

        // return objects
        val returnObjects = ArrayList<DocumentWithHighlights>()

        for (document in documents) {

            // make a new return object
            returnObjects.add(DocumentWithHighlights(document,
                    getFragments(document, highlighter)))
        }

        return returnObjects
    }

    @Throws(Exception::class)
    private fun getFragments(document: Document, highlighter: Highlighter): Array<String> {

        // get the fragments
        val stream = MyAnalyzer.wrapperAnalyzer().tokenStream("body", document.get("body"))
        val highlightData = highlighter.getBestFragments(stream, document.get("body"), 10)

        return highlightData
    }
}
